use std::collections::HashMap;
use std::time::Duration;

use async_trait::async_trait;
use dbus::arg;
use dbus::nonblock;
use dbus::nonblock::stdintf::org_freedesktop_dbus::*;

use crate::consts::*;
use crate::Result;

mod adapter;
mod advertising;
mod agent;
mod device;
mod gatt;
mod health;
mod input;
mod media;
mod mgmt;
mod network;
mod obex;
mod obex_agent;
mod profile;
// mod root;
mod sap;

pub use adapter::*;
pub use agent::*;
pub use device::*;
// pub use root::*;

pub struct OrgBluezObjectManager<T, C>
where
    T: nonblock::NonblockReply,
    C: std::ops::Deref<Target = T> + Sync + Clone,
{
    proxy: nonblock::Proxy<'static, C>,
    timeout: Duration,
}

impl<T, C> OrgBluezObjectManager<T, C>
where
    T: nonblock::NonblockReply,
    C: std::ops::Deref<Target = T> + Sync + Clone,
{
    pub fn new(conn: C, timeout: Duration) -> Self {
        let proxy = nonblock::Proxy::new(DBUS_BLUEZ_SERVICE, "/", timeout, conn);
        Self { proxy, timeout }
    }

    pub async fn list_adapters(&self) -> Result<Vec<nonblock::Proxy<'static, C>>> {
        let objects = self.proxy.get_managed_objects().await?;
        let mut adapters = vec![];
        for (path, mo) in objects {
            for (i, _) in mo {
                if i.as_str() == DBUS_BLUEZ_IFACE_ADAPTER {
                    let adapter = nonblock::Proxy::new(
                        DBUS_BLUEZ_SERVICE,
                        path.to_string(),
                        self.timeout,
                        self.proxy.connection.clone(),
                    );
                    adapters.push(adapter)
                }
            }
        }
        Ok(adapters)
    }

    pub async fn list_devices(&self) -> Result<Vec<nonblock::Proxy<'static, C>>> {
        let objects = self.proxy.get_managed_objects().await?;
        let mut devices = vec![];
        for (path, mo) in objects {
            for (i, _) in mo {
                if i.as_str() == DBUS_BLUEZ_IFACE_DEVICE {
                    let dev = nonblock::Proxy::new(
                        DBUS_BLUEZ_SERVICE,
                        path.to_string(),
                        self.timeout,
                        self.proxy.connection.clone(),
                    );
                    devices.push(dev)
                }
            }
        }
        Ok(devices)
    }
}
